#!/bin/bash -e

#========================================================
# Generates IDE files, runs tests and analysis for
# example projects
# 
# By default this will do all of the above. You can
# selectively disable behaviour by setting the following 
# enviroment variables:
# 
# GENERATE_IDE_PROJECTS:    Set to 1 to generate default IDE files
# DISABLE_BUILD:            Set to 1 to disable standard building
# ENABLE_ASAN:              Set to 1 to enable ASan builds
# ENABLE_TSAN:              Set to 1 to enable TSan builds
# ENABLE_STATIC_ANALYSER:   Set to 1 to enable Static Analyser builds
# 
#========================================================

#========================================================
# Configure build environment
#========================================================
cmake --version

if [[ "$OSTYPE" == "linux-gnu" ]]; then PLATFORM=linux
elif [[ "$OSTYPE" == "darwin"* ]]; then PLATFORM=mac
elif [[ "$OSTYPE" == "msys" ]];    then PLATFORM=windows
fi

if [ -z "$PLATFORM" ]; then
    echo ERROR: Unknown platform
    exit 1
fi

ROOT=$(cd "$(dirname "$0")/.."; pwd)
EXAMPLES_ROOT="$ROOT/examples"

if [ -z "$ROOT" ]; then
    echo "ERROR: Unknown workspace"
    exit 1
fi

if [ ! -d "$ROOT/modules/juce/modules" ]; then
    echo "ERROR: juce library module not preset!"
    exit 1
fi

echo "\n=========================================="
echo PLATFORM: "$PLATFORM"
echo ROOT: "$ROOT"
echo DISABLE_BUILD: "$DISABLE_BUILD"
echo ENABLE_ASAN: "$ENABLE_ASAN"
echo ENABLE_TSAN: "$ENABLE_TSAN"
echo ENABLE_STATIC_ANALYSER: "$ENABLE_STATIC_ANALYSER"


#============================================================
#   Build an example
#============================================================
function buildExample()
{
    PROJECT_NAME="$1"

    if [ -z "$PROJECT_NAME" ]; then
        echo "ERROR: Must supply a project name!"
        exit 1
    fi

    #============================================================
    #   Configure build vars
    #============================================================
    EXAMPLE_DIR="${EXAMPLES_ROOT}/${PROJECT_NAME}"
    CMAKE_BUILD_DIR="${EXAMPLE_DIR}/build"

    if [[ "$PLATFORM" == "linux" ]]; then
        BINARY_NAME="$PROJECT_NAME"
        APP_NAME=$BINARY_NAME
        APP_DIR="${CMAKE_BUILD_DIR}/${PROJECT_NAME}_artefacts/Release"
        APP_FILE=$APP_DIR/$BINARY_NAME
        APP_BINARY="$APP_FILE"

        # Use the default Unix Makefiles cmake generator
        CMAKE_GENERATOR=""
        CMAKE_PLATFORM_ARGS="-DCMAKE_BUILD_TYPE=Release"
        CMAKE_BUILD_PLATFORM_ARGS="--parallel `nproc`"
    elif [[ "$PLATFORM" == "mac" ]]; then
        BINARY_NAME="$PROJECT_NAME"
        APP_NAME=$BINARY_NAME
        APP_DIR=$CMAKE_BUILD_DIR/${PROJECT_NAME}_artefacts/Release
        APP_FILE=$APP_DIR/$APP_NAME
        APP_BINARY="$APP_FILE/Contents/MacOS/${PROJECT_NAME}"

        CMAKE_GENERATOR="-G Xcode"
    elif [[ "$PLATFORM" == "windows" ]]; then
        BINARY_NAME="$PROJECT_NAME".exe
        APP_NAME="$BINARY_NAME"
        APP_DIR=$CMAKE_BUILD_DIR/${PROJECT_NAME}_artefacts/Release
        APP_FILE="$APP_DIR/$BINARY_NAME"
        APP_BINARY="$APP_FILE"

        # Use the default VS cmake generator
        CMAKE_GENERATOR=""
        CMAKE_PLATFORM_ARGS="-A x64"

        if [ -z "$MSBUILD_EXE" ]; then
            echo MSBuild not found at "${MSBUILD_EXE}", using default
            MSBUILD_EXE=$("/c/Program Files (x86)/Microsoft Visual Studio/Installer/vswhere" -latest -requires Microsoft.Component.MSBuild -find "MSBuild\**\Bin\MSBuild.exe")
        fi

        if [ ! -f "$MSBUILD_EXE" ]; then
            echo MSBuild.exe not found at "${MSBUILD_EXE}" export this env var to the MSBuild.exe location on your system before running this script
            exit 1
        fi
    fi

    echo PROJECT_NAME: "$PROJECT_NAME"
    echo BINARY_NAME: "$BINARY_NAME"
    echo APP_NAME: "$APP_NAME"
    echo APP_DIR: "$APP_DIR"
    echo APP_FILE: "$APP_FILE"
    echo CMAKE_BUILD_DIR: "$CMAKE_BUILD_DIR"
    echo CMAKE_GENERATOR: "$CMAKE_GENERATOR"    
    
    # Capture named function arguments
    local global RUN_EXAMPLE ENABLE_ASAN ENABLE_TSAN RUN_ARGS ${@}
    echo DISABLE_BUILD: $DISABLE_BUILD
    echo RUN_EXAMPLE: $RUN_EXAMPLE
    echo ENABLE_ASAN: "$ENABLE_ASAN"
    echo ENABLE_TSAN: "$ENABLE_TSAN"
    echo ENABLE_STATIC_ANALYSER: "$ENABLE_STATIC_ANALYSER"
    echo RUN_ARGS: $RUN_ARGS

    #============================================================
    #   Build
    #============================================================
    # rm -rf "$CMAKE_BUILD_DIR"
    cd "$EXAMPLE_DIR"
    pwd

    function generateBuildFiles()
    {
        echo INFO: Generating build files: ${APP_FILE}
        cmake -B "$CMAKE_BUILD_DIR" $CMAKE_GENERATOR $CMAKE_PLATFORM_ARGS
    }

    # Conditionally generate the IDE files for the generate_examples script
    if [ "$GENERATE_IDE_PROJECTS" == "1" ]; then
        generateBuildFiles
    fi

    # Conditionally build and run project
    if [ "$DISABLE_BUILD" == "1" ]; then
        echo INFO: Not building example: ${APP_FILE}
    else
        generateBuildFiles

        cmake --build "$CMAKE_BUILD_DIR" --target "$PROJECT_NAME" --config Release $CMAKE_BUILD_PLATFORM_ARGS

        if [ "$RUN_EXAMPLE" == "1" ]; then
            echo INFO: Running example: ${APP_FILE}
            ${APP_FILE} ${RUN_ARGS} --junit-xml-file "$ROOT/bin/test_results/TEST-${APP_NAME}.xml"
        else
            echo INFO: Not running example: ${APP_FILE}
        fi
    fi

    # Conditionally build and run tooled projects
    if [ "$PLATFORM" = "mac" ]; then
        if [ "$ENABLE_ASAN" == "1" ]; then
            generateBuildFiles

            echo INFO: Running with Asan: ${APP_FILE}
            cmake --build "$CMAKE_BUILD_DIR" --target "$PROJECT_NAME" --config Release -- -enableAddressSanitizer YES LLVM_LTO=NO GCC_PREPROCESSOR_DEFINITIONS='$GCC_PREPROCESSOR_DEFINITIONS GRAPH_UNIT_TESTS_QUICK_VALIDATE=1'
            ${APP_FILE} --junit-xml-file "$ROOT/bin/test_results/TEST-${APP_NAME}_asan.xml"
        fi

        if [ "$ENABLE_TSAN" == "1" ]; then
            generateBuildFiles

            echo INFO: Running with Tsan: ${APP_FILE}
            cmake --build "$CMAKE_BUILD_DIR" --target "$PROJECT_NAME" --config Release -- -enableThreadSanitizer YES LLVM_LTO=NO GCC_PREPROCESSOR_DEFINITIONS='$GCC_PREPROCESSOR_DEFINITIONS GRAPH_UNIT_TESTS_QUICK_VALIDATE=1'
            ${APP_FILE} --junit-xml-file "$ROOT/bin/test_results/TEST-${APP_NAME}_tsan.xml"
        fi

        if [ "$ENABLE_STATIC_ANALYSER" == "1" ]; then
            generateBuildFiles
            cd "$CMAKE_BUILD_DIR"

            echo INFO: Running static analyser: ${APP_FILE}
            xcodebuild analyze -quiet -target "$PROJECT_NAME" -configuration Release LLVM_LTO=NO
        fi
    else
        echo INFO: Platform not mac: ${APP_FILE}
        echo PLATFORM: "$PLATFORM"
    fi
}


# First build and test these examples
buildExample "TestRunner" RUN_EXAMPLE=1 ENABLE_ASAN=$ENABLE_ASAN ENABLE_TSAN=$ENABLE_TSAN
buildExample "Benchmarks" RUN_EXAMPLE=1 ENABLE_ASAN=0 ENABLE_TSAN=0

# Then just build these examples (don't build with tooling as they won't be run)
buildExample "DemoRunner" ENABLE_ASAN=0 ENABLE_TSAN=0
buildExample "EngineInPluginDemo" ENABLE_ASAN=0 ENABLE_TSAN=0
